package ace.oauth2.provider.base.support;


import ace.oauth2.provider.common.properties.OAuth2Property;
import lombok.AllArgsConstructor;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;

import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

/**
 * @author Caspar
 * @contract 279397942@qq.com
 * @create 2020/10/21
 * @description default token enhancer
 */
@AllArgsConstructor
public class DefaultTokenEnhancer implements TokenEnhancer {
    private OAuth2Property oAuth2Property;

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        if (Objects.isNull(authentication.getUserAuthentication()) ||
                Objects.isNull(authentication.getUserAuthentication().getPrincipal())) {
            return accessToken;
        }
        UserDetails userDetails = (UserDetails) authentication.getUserAuthentication().getPrincipal();
        Map<String, Object> additionalInfo = this.getUserAdditionalInfo(userDetails);
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
        return accessToken;
    }


    private Map<String, Object> getUserAdditionalInfo(UserDetails userDetails) {
        if (CollectionUtils.isEmpty(oAuth2Property.getUserAdditionalInfoProperty())) {
            return MapUtils.EMPTY_SORTED_MAP;
        }

        Map<String, Object> additionalInfo = new TreeMap<>();

        oAuth2Property.getUserAdditionalInfoProperty().forEach(p -> {
            Object value = null;
            try {
                value = PropertyUtils.getProperty(userDetails, p);
                additionalInfo.put(p, value);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        });

        return additionalInfo;
    }
}
